/** 面向画布操作
 * 内部属性说明；
 *    box: 最外层，决定画布大小，负责监听事件（因需要键盘事件，属性为可编辑）
 *    homeEl：包裹canvas，负责隔离box的编辑属性、canvas位置信息
 *    canvas、ctx：画布、操作画布
 *    downloadBtn：导出图片按钮（隐藏）
 *    maxX | maxY - 容器大小
 *    pageX | pageY - 容器距离页面位置（用于计算内部相对位置）
 *    option - 画图配置
 *      clipbrdType 剪贴板类型 'in'内部 'out'外部
 *      pxWidth - 像素
 *      foregroundColor - 填充色
 *      backgroundColor - 背景色
 *      scale - 缩放（清晰度）
 *      boxWidth| boxHeight - 画布实际大小
 * 公共工具（略）
 *    * */
import {EVENT_TYPES} from "./var";
import html2canvas from 'html2canvas';

export class Base {
  constructor(option) {
    // 1.初始化元素并设置标识
    this.initHome(option.selector);
    this.initCanvas(option.selector);
    this.option = {
      clipbrdType: 'out'
    };
    // 初始化配置
    this.setOption(option, true);
  }
  /** 初始化 */
  initHome(selector) {
    this.box = document.querySelector(selector);
    this.box.setAttribute('contenteditable', "true");
    this.box.setAttribute('data-draw-role', "EventHome");
    // 包裹画布（不受父元素contenteditable影响）
    this.homeEl = document.createElement('div');
    this.homeEl.style.width = '100%';
    this.homeEl.style.height = '100%';
    this.homeEl.setAttribute('contenteditable', "false");
    this.box.appendChild(this.homeEl);
  }
  initCanvas(selector) {
    // 设置像素比 todo ie不支持
    if (window.devicePixelRatio) {
      window.devicePixelRatio = 1;
    }
    // 获取容器
    const canvasBox = this.homeEl;
    canvasBox.classList.add('draw-box');
    const width = canvasBox.clientHeight;
    const height = canvasBox.clientWidth;
    this.option = {
      boxSelector: selector,
      boxEl: canvasBox,
      boxWidth: width,
      boxHeight: height,
      scale: 1, // 缩放
      pxWidth: 3, // 画笔像素
      foregroundColor: 'black', // 前景色
      backgroundColor: '#fff' // 背景色
    };

    // 创建画布
    const canvas = document.createElement('canvas');
    canvas.classList.add('draw-canvas');
    canvas.setAttribute('eventType', EVENT_TYPES.darwerEvenType);
    const ctx = canvas.getContext('2d');
    this.canvas = canvas;
    this.ctx = ctx;
    canvasBox.appendChild(canvas);
    return this;
  }

  /** 配置 */
  // 设置配置
  async setOption(option, isinit) {
    this.option = Object.assign(this.option, option);
    if (!isinit) {
      const base64 = await this.toBase64(this.canvas);
      if (
        (!!option.scale && this.option.scale !== option.scale) ||
        (!!option.boxWidth && this.option.boxWidth !== option.boxWidth) ||
        (!!option.boxHeight && this.option.scale !== option.boxHeight)
      ) {
        this.readSize();
        this.resizeDarwer();
      }
      await this.base642Ctx(this.ctx, base64, 0, 0);
    } else {
      this.resizeDarwer();
    }
  }
  // 重置画布大小、清晰度
  resizeDarwer() {
    this.readSize();
    const o = this.option;
    const v = o.scale;
    this.canvas.style.width = `${o.boxWidth}px`;
    this.canvas.style.height = `${o.boxHeight}px`;
    this.canvas.width = o.boxWidth * v;
    this.canvas.height = o.boxHeight * v;
    this.ctx.scale(v, v); //再来设置比例
    // 画布背景初始化
    this.ctx.fillStyle = '#aaa';
    this.ctx.beginPath();
    this.ctx.rect(0, 0, this.maxX, this.maxY);
    this.ctx.fill();
    this.ctx.closePath();
  }

  /** 画布操作*/
  // 读取元素大小、位置
  readSize() {
    // 获取元素位置、大小信息，注意小数
    const {top, left, width, height} = this.homeEl.getBoundingClientRect();
    this.maxX = width;
    this.maxY = height;
    this.pageX = Math.round(left);
    this.pageY = Math.round(top);
  }
  // dom转Base64码
  toBase64(dom, type = 'image/png') {
    return new Promise((resolve, reject) => {
      html2canvas(dom, {backgroundColor: '#00000000'}).then((canvas) => {
        const copyImg = canvas.toDataURL(type);
        resolve(copyImg);
      });
    });
  }
  // Base64码粘贴到ctx
  base642Ctx(ctx = this.ctx, base64, left, top) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.src = base64;
      img.height = 200;
      img.width = 200;
      img.onload = _ => {
        ctx.drawImage(img, left, top);
        resolve(true);
      };
      img.onerror = _ => {
        reject(false);
      };
    });
  }
  // 按矩形区域剪切 or 复制到目标cavans
  cutOrCopy(fromCtx = this.ctx, toCtx, {x, y, w, h}, type = 'cut') {
    const imageDtas = fromCtx.getImageData(x, y, w, h);
    toCtx.putImageData(imageDtas, 0, 0);
    if (type === 'cut') {
      this.ctx.beginPath();
      this.ctx.fillStyle = this.option.backgroundColor;
      this.ctx.rect(x, y, w, h);
      this.ctx.fill();
      this.ctx.closePath();
    }
  }

  /** 工具 */
  // 计算实际像素
  checkXYPX({x, y}) {
    x *= this.option.scale;
    y *= this.option.scale;
    return {x, y};
  }
  // 获取RGBA颜色值
  getRgbaFromColor(color = this.option.foregroundColor) {
    if (!this._singlePixelCanvas) {
      const canvas = document.createElement('canvas');
      canvas.ctx = canvas.getContext('2d');
      canvas.width = 1;
      canvas.height = 1;
      this._singlePixelCanvas = canvas;
    }
    this._singlePixelCanvas.ctx.fillStyle = color;
    this._singlePixelCanvas.ctx.fillRect(0, 0, 1, 1);
    let id = this._singlePixelCanvas.ctx.getImageData(0, 0, 1, 1);
    return Array.from(id.data);
  }

  // 导出图片
  async exportImg() {
    if (!this.downloadBtn) {
      this.downloadBtn = document.createElement('a');
      this.downloadBtn.download = '画图.png';
    }
    const base64 = await this.toBase64(this.canvas, 'image/jpg');
    this.downloadBtn.href = base64;
    this.downloadBtn.click();
  }
}